home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Merciful 1
/
Merciful - Disc 1.iso
/
software
/
f
/
friday_night_pool
/
fridaynightpool.dms
/
fridaynightpool.adf
/
source
/
fnpool.c
< prev
next >
Wrap
C/C++ Source or Header
|
1978-02-25
|
29KB
|
1,061 lines
#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/view.h>
#include <intuition/intuition.h>
#include <graphics/gfxmacros.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <dos.h>
#include <proto/dos.h>
#include <math.h>
#include <exec/devices.h>
#include <devices/audio.h>
#include <hardware/custom.h>
#define CUE 0
#define BLK 5
#define GREENBAIZE 0
#define BLUEBAIZE 1
#define BASE 200 /* V.important constant. Used in ALL physical calcs. */
#define BASESP 1000
#define BASEII 4 /* For root calcs which need plenty of precision */
#define TABLELENGTH (272 * BASE) /* 272 is actual length in pixels */
#define TABLEWIDTH ((TABLELENGTH * 5 / 8)-BASE)
#define X1CORNER 24
#define Y1CORNER 62
#define X2CORNER (X1CORNER + TABLELENGTH / BASE)
#define Y2CORNER (Y1CORNER + TABLEWIDTH / BASE)
#define BALLRADIUS (7 * BASE) /* 7 pixels */
#define BALLDIAMETER (BALLRADIUS * 2)
#define SCRNBALLDIAMETER (BALLDIAMETER / BASE)
#define SEMICIRCRAD (TABLEWIDTH/6)
#define PLACEPACK (TABLELENGTH * 5 / 8)
#define PACKHORIZSEP (BALLDIAMETER - 2*BASE)
#define POCKET (BALLRADIUS + 5*BASE)
#define SCRNPOCKET (POCKET / BASE)
#define CUETIP 10
#define MAXCUELENGTH 80
#define CLOCKWISE 1
#define ANTICLOCKWISE 2
#define SMALL 1
#define LARGE 2
#define UP 1
#define DOWN 2
#define NOHIT -1
#define ON TRUE
#define OFF FALSE
#define HIT 3
#define UPDATE 3
#define ICON 2
#define VIEW 1
#define NOREFRESH 2
#define RACKED 1
#define BROKEN 0
#define OPEN 2
#define SPREAD 3
#undef SINGLE
enum icons { PLYR1,PLYR2,PRACTICE,DEMO,PLAY,QUIT,_BAIZE,_BALL1,_BALL2,
SINGLE,BEST3,BEST5,UNLIMITED,STRIP,BALL10,BALL16,
OPPONENTBASE,ICON17,ICON18,ICON19,STRIPPERBASE };
enum args { GAMETYPE,GAMELENGTH,BAIZE,BALL1,BALL2,BALLCOUNT,OPPONENT,STRIPPER };
#define HUMANPLYR 0
#define COMPLYR 1
#define FRICTION (BASESP / 300)
#define SPINFRICTION 3
#define SPEEDINC (BASESP / 16)
#define MAXSPEED (BASESP * 4)
#define MINSPEED (BASESP / 4)
#define ESC 69
#define RETURN 68
#define SPACE 64
#define HELP 95
#define LCSR 79
#define RCSR 78
#define UCSR 76
#define DCSR 77
#define F1 80
#define F2 81
#define F3 82
#define F4 83
#define F5 84
#define F6 85
#define F7 86
#define F8 87
#define F9 88
#define F10 89
#define FLASH 2
#define JOYFIRE 0xbfe001
#define LMOUSE 1
#define RMOUSE 2
#define MEMSIZE 7000
void DoControl(void);
void DrawCue(short);
void ChangePower();
short ChangeSpin(void);
void DrawCross(short);
void MoveCue(short,short);
void DoAssigns(void);
void SetUpTable(void);
void DoOptions(void);
short GetInput(void);
char UpdateBallPos(void);
void WaitBeam(short);
short CheckPotted(short);
void CheckBounce(short);
void CheckCollision(void);
void MakeCollision(short,short);
void DrawBall(short,short);
void DrawBallDirect(short,short,short);
short FindAngle(WORD,WORD,WORD);
void SuperImpose(struct RastPort *,short,short,struct RastPort *,
short,short,short,short,short,short);
void WriteMessage(short,short,short,short);
void ScrubMessage(void);
void PlayShot(void);
void CheckResult(void);
void CheckWhitePotted(void);
short TouchingBall(short);
void PlayComputerShot(void);
void CheckBallDrag(void);
void CopyBalls(struct ballstruct*,struct ballstruct*);
void CopyPlayer(short,short);
WORD QuickRoot(long);
short GetMouse(void);
char LoadIFF(struct IFFGraphic *,struct Screen *,char);
char ClickDelay(short);
void CueJumpAnim(void);
void CheckAngle(short *);
UWORD Rand(UWORD);
long MyRead(struct FileHandle *,long *,long);
char OpenIt(void);
void CloseIt(void);
APTR GetDeviceBlock(ULONG);
void FreeDeviceBlock(struct IOAudio *,BYTE);
void Audio_PerVol(struct IOAudio *,UWORD,UWORD);
void Audio_Write(struct IOAudio *,UBYTE *,UWORD);
void PlaySound(struct audioinfostruct *,short);
/******************* Graphics defines ******************/
struct NewScreen ns =
{
0,0, /* Left edge, top */
320,256, /* Width, height */
5, /* Depth (32 colours) */
0,1, /* Detail, block pens */
0, /* Modes for ViewPort */
CUSTOMSCREEN | SCREENQUIET,
/* Screen type */
NULL, /* Text attributes */
NULL, /* Title */
NULL, /* Gadget list */
NULL /* Custom bitmap pointer */
};
struct NewWindow nw =
{
0,0, /* Starting corner */
320,256, /* Width, height */
0,1, /* detail, block pens */
RAWKEY, /* IDCMP flags */
BORDERLESS | ACTIVATE | RMBTRAP,
/* Window flags */
NULL, /* Pointer to first gadget */
NULL, /* Pointer to checkmark */
NULL, /* title */
NULL, /* screen pointer (don't know yet) */
NULL, /* bitmap pointer */
0,0,0,0, /* window not sized */
CUSTOMSCREEN /* type of screen */
};
/* Extra padding for use with tempmask. Must set ballmask to point to */
/* first 'real' byte (8) at start of program */
USHORT chip crossmask[5] = { 0x2000,0x2000,0xd800,0x2000,0x2000 };
USHORT chip mask[37] = { 0,0,0,0,0,0,0,0,0,0,0,0,
0x3e0,0xff8,0x1ffc,0x1ffc,0x3ffe,0x3ffe,
0x3ffe,0x3ffe,0x3ffe,0x1ffc,0x1ffc,0xff8,0x3e0,
0,0,0,0,0,0,0,0,0,0,0,0 };
USHORT chip mask2[10] = { 0x3e0,0xff0,0xff8,0x1ff8,0x1ff8,0x1ff8,
0x1ff0,0x1ff0,0xfe0,0x780 };
USHORT chip hybridmask[13] =
{ 0x3e0,0xff8,0x7fc,0x3fc,0x1fe,0xfe,0x7e,0x3e,0x1e,0xc,0x4,0,0 };
USHORT chip hybridmask2[10] =
{ 0x3e0,0x7f0,0x3f8,0x1f8,0x0f8,0x078,0x030,0x010,0,0 };
USHORT chip miniball[8] =
{ 0x3c00,0x7e00,0xff00,0xff00,0xff00,0xff00,0x7e00,0x3c00 };
USHORT *ballmask = &mask[12];
USHORT *ballmask2 = mask2;
USHORT chip tempmask[256];
USHORT chip buffer[20];
/********************* System defines ************************/
struct Screen *s,*s2;
struct Window *w,*w2;
struct RastPort *rp,*rp2,bufrp;
struct BitMap *bm,*bm2,bufbm;
struct ViewPort *vp;
struct ColorMap *cm;
struct IntuiMessage *msg;
struct FileHandle *fh;
struct Preferences prefs;
UWORD *colorpalette;
char *bp0,*bp1,*bp2,*bp3,*bp4;
extern UWORD chip pointeron[24];
extern UWORD chip pointeroff[8];
long oldkeydelay,oldkeyspeed;
/******************* Audio Defines ******************/
#define SAMPLES 8
#define AM2 106 /* Audio Master II info size */
#define BUFWAVELEN 100
enum sound { COLLIDE,STRIKE,BOUNCE,POTTED,CHEER,LONGCHEER,CHANT,CRASH };
#define AUDIO_LEN (sizeof(struct IOAudio))
#define PRECIDENCE 127
#define CLOSE_DEVICE 1
#define BUFFER 0
#define RESET 1
struct IOAudio *audio[4];
char Channel_Map[] = { 1,2,4,8 },*bufwave;
struct audioinfostruct
{
struct IOAudio *audio;
char *wave,bufstate,channel,flag;
long wavelen;
short volume,period;
char filename[30];
};
struct audioinfostruct audioinfo[SAMPLES] = {
{ 0,0,0,0,BUFFER,702-AM2,0,320,"FNPAUDIO:collide.sam" },
{ 0,0,0,1,BUFFER,544-AM2,0,600,"FNPAUDIO:strike.sam" },
{ 0,0,0,2,RESET,448-AM2,0,640,"FNPAUDIO:bounce.sam" },
{ 0,0,0,3,BUFFER,1386-AM2,0,315,"FNPAUDIO:pot.sam" },
{ 0,0,0,2,RESET,19708-AM2,0,550,"FNPAUDIO:cheer.sam" },
{ 0,0,0,2,RESET,36682-AM2,0,550,"FNPAUDIO:cheer2.sam" },
{ 0,0,0,2,RESET,20432-AM2,0,536,"FNPAUDIO:chant.sam" },
{ 0,0,0,2,RESET,18960-AM2,0,286,"FNPAUDIO:crash.sam" }};
/********************* Gameplay defines **********************/
UWORD rgb[32];
UWORD rgb2[32] = {
0x000,0xfb9,0xd86,0x593,0x030,0x400,0x610,0x820,
0x150,0xfc0,0xf00,0x382,0xfff,0xfff,0xfcc,0x270,
0x444,0xb8b,0x000,0xfff,0xf83,0xfc7,0x000,0x000,
0x000,0xfff,0x888,0x000,0x9cf,0x000,0x000,0x000 };
enum col {
_back,_leather,_dkleather,_ltbaize,_dkbaize,_dkwalnut,_walnut,_ltwalnut,
_baize,_yellow,_red,_ltbaize2,_white,_highyel,_highred,_ltbaize3,
_cross,_ptr17,_ptr18,_ptr19,_cuecol,_ltcuecol,_22,_23,
_black,_text1,_text2 };
enum balltype { white,black,yellow,red,anyball,baize };
char ballpalette[] = { _white,_black,_yellow,_red, 0,_baize };
char ball15colour[16] = {
white,yellow,red,yellow,yellow,black,red,red,
yellow,red,yellow,yellow,red,yellow,red,red };
char ball9colour[10] = {
white,red,red,red,red,black,red,red,red,red };
char ballplanes[] = { 4,16,1,2, 0,23 };
struct ballstruct
{
enum balltype colour;
char potted,justpotted,hasmoved,lasthit,olddx,olddy;
USHORT x,y;
short speed,angle,scrnx,scrny,oldscrnx,oldscrny;
};
struct ballstruct ball[16],tempball[16];
struct pixelsavestruct
{
char col;
short x,y;
};
struct pixelsavestruct pixelsave[32];
struct blitdatstruct
{
short x,y,dx,dy;
};
struct blitdatstruct blitdat,blitdat2;
char *quickarcsin;
short *memblock,*quicksin,*quickcos,
cueangle=270,cuespeed=MINSPEED,powerdirn=UP,
spinx,spiny,swerve,swervetotal,
gametype,gamelength,stripper,opponent,
defaultdemo,enableoptions=TRUE,flipoffer,
cloth,cueline=ON,firsthit,dotspacing=8,cheer=ON,
plyrbreak,turn,comp1,comp2,
balls=16,dragcheat,cheatangle=-1,cheatball,
foul,endofgame,quitgame,winner,matches,coin,packstate,newbreak;
USHORT seed; /* random element */
USHORT pocketx[6] = { (TABLELENGTH-BALLRADIUS),(TABLELENGTH-BALLRADIUS),
(TABLELENGTH/2),(TABLELENGTH/2),BALLRADIUS,BALLRADIUS };
USHORT pockety[6] = { (TABLEWIDTH-BALLRADIUS),BALLRADIUS,
(TABLEWIDTH-BALLRADIUS),BALLRADIUS,(TABLEWIDTH-BALLRADIUS),BALLRADIUS };
char angleused[360];
char joydelay;
extern struct Custom far custom;
/********* Loader stuff *************/
extern struct IFFGraphic
{
char FileName[30]; /* Name of IFF file */
BYTE ReqDepth; /* How many bitplanes wish to be Displayed */
USHORT *RGB; /* RGB colour values, filled by LoadIFF */
short Width; /* Width of graphic, filled by LoadIFF */
short Height; /* Height of graphic, filled by LoadIFF */
BYTE Depth; /* Depth of graphic, filled by LoadIFF */
};
extern char arg[8],bufarg[8],demoarg[8];
struct IFFGraphic
tableIFF = { "FNPGRAPHICS:table.img",5,NULL },
offerIFF = { "FNPGRAPHICS:offer.img",5,rgb },
offer2IFF = { "FNPGRAPHICS:offer2.img",5,rgb };
UWORD RGBbaize[] = {
0x593,0x030,0x150,0x382,0x270, /* green */
0x368,0x023,0x034,0x156,0x145, /* blue */
0x965,0x421,0x632,0x854,0x743, /* brown */
0x777,0x333,0x444,0x666,0x555 }; /* grey */
UWORD RGBball[] = { 0xf00,0xf40,0xfa0,0x390,0x05f,0x608,0xf55 };
UWORD RGBroom[16];
/********** Strip stuff *****************/
struct IFFGraphic roomIFF = { "FNPGRAPHICS:room.img",5,RGBroom };
struct IFFGraphic stripimageIFF[4] = {
{ "FNPGRAPHICS:claire_sally.img",5,rgb },
{ "FNPGRAPHICS:michael.img",5,rgb },
{ "FNPGRAPHICS:claire_sally.img",5,rgb },
{ "FNPGRAPHICS:josh.img",5,rgb }};
struct IFFGraphic striptextIFF[4] = {
{ "FNPGRAPHICS:quotes.img",5,rgb },
{ "FNPGRAPHICS:quotes.img",5,rgb },
{ "FNPGRAPHICS:quotes.img",5,rgb },
{ "FNPGRAPHICS:quotes2.img",5,rgb }};
struct stripstruct
{
short imgx1[4],imgy1[4],imgdx[4],imgdy[4],imgx2[4],imgy2[4],
textx[5],texty[5],textdx[5],textdy[5];
};
struct stripstruct stripinfo[4] = {
{ 192,129,65,0, 0,0,0,0, 60,60,60,60,
139,139,139,139, 19,19,19,19, 68,68,68,68,
0,113,89,0,207, 0,0,39,39,39, 112,200,117,88,88, 32,39,39,32,32 },
{ 195,128,61,0, 0,0,0,0, 65,65,65,58,
149,149,149,149, 11,11,11,11, 57,57,57,57,
135,0,0,237,148, 80,172,211,153,153, 110,147,118,82,88, 32,39,41,53,32 },
{ 211,140,70,0, 139,139,139,139, 67,67,67,67,
112,112,112,112, 27,27,27,27, 90,90,90,90,
0,135,0,224,245, 133,113,80,113,80, 117,88,133,81,75, 39,32,53,39,32 },
{ 170,108,57,0, 0,0,0,0, 56,56,50,50,
171,171,161,161, 17,28,23,23, 50,51,50,50,
0,0,171,0,139, 60,0,0,106,60, 139,171,149,131,113, 46,60,53,46,53 }};
/******* Message stuff *****************/
#define NEW 0
#define FOLLOW 1
enum msg { MSG_PLACECUEBALL,MSG_FOUL,MSG_WINS,MSG_MICHAEL,MSG_JOSH,
MSG_CLAIRE,MSG_SALLY,MSG_PLAYER1,MSG_PLAYER2,MSG_QUITTING,
MSG_VS,MSG_GAME,MSG_OF,MSG_0,MSG_1,MSG_2,MSG_3,MSG_4,MSG_5,
MSG_GOODSHOT,MSG_SHOTCANCELLED,MSG_BADLUCK,MSG_WELLDONE,
MSG_QUITGAME,MSG_ISTHECHAMP,MSG_OOOPS };
short cursor;
struct messagestruct { short x1,y1,x2,y2; };
struct messagestruct message[] = {
{ 0,0,122,13 }, { 123,0,174,13 }, { 175,0,214,13 }, { 215,0,275,13 },
{ 276,0,313,13 },
{ 0,14,44,31 }, { 45,14,82,31 }, { 83,14,144,31 },
{ 145,14,208,31 }, { 209,14,284,31 }, { 285,14,301,31 },
{ 0,32,44,45 }, { 45,32,60,45 }, { 240,60,253,77 }, { 61,32,64,45 },
{ 65,32,72,45 }, { 73,32,80,45 }, { 81,32,89,45 }, { 90,32,97,45 },
{ 98,32,196,45 }, { 197,32,317,45 },
{ 0,46,74,59 }, { 75,46,160,59 },
{ 0,60,127,77 }, { 128,60,239,77 }, { 240,60,299,77 }};
/************ Player stuff **************/
struct playerstruct
{
enum balltype colour;
char goes,wins;
char nametag;
short maxpower;
char cuepulls,skill;
};
struct playerstruct player[8] = {
{ 0,0,0,0,MAXSPEED,0,0 }, /* Filled 1 */
{ 0,0,0,0,MAXSPEED,0,0 }, /* Filled 2 */
{ 0,0,0,MSG_PLAYER1,MAXSPEED,1,3 }, /* Player 1 */
{ 0,0,0,MSG_PLAYER2,MAXSPEED,1,3 }, /* Player 2 */
{ 0,0,0,MSG_CLAIRE,MAXSPEED,2,0 }, /* Claire */
{ 0,0,0,MSG_MICHAEL,MAXSPEED+MAXSPEED/2,0,2 }, /* Mike */
{ 0,0,0,MSG_SALLY,MAXSPEED-MAXSPEED/4,1,3 }, /* Sally */
{ 0,0,0,MSG_JOSH,MAXSPEED,3,3 }}; /* Josh */
/**********************/
main()
{
short i,match;
if (!OpenIt()) { CloseIt(); return; }
DoAssigns();
if (Loader(1)) do
{
coin=-1; DoOptions();
switch(gamelength)
{
case BEST3:
case BEST5:
for(match=0; match<matches; match++)
{
WriteMessage(MSG_GAME,5,5,NEW);
WriteMessage(MSG_1+match,0,5,FOLLOW);
WriteMessage(MSG_OF,0,5,FOLLOW);
WriteMessage((MSG_1-1)+matches,0,5,FOLLOW);
SetUpTable(); Delay(100); DoControl();
if (player[0].wins>matches/2 ||
player[1].wins>matches/2 ||
quitgame) break;
WriteMessage(player[1-winner].nametag,5,5,NEW);
WriteMessage(MSG_0+player[1-winner].wins,15,5,FOLLOW);
Delay(65);
WriteMessage(player[winner].nametag,5,5,NEW);
WriteMessage(MSG_0+player[winner].wins,15,5,FOLLOW);
Delay(65);
}
if (!quitgame)
{
FadeScreen(s,DOWN); SetRast(rp,_back);
WriteMessage(player[winner].nametag,60,80,NEW);
WriteMessage(MSG_ISTHECHAMP,0,80,FOLLOW);
FadeScreen(s,UP); ClickDelay(400);
} break;
case SINGLE:
SetUpTable(); DoControl(); break;
case UNLIMITED:
do
{ SetUpTable(); DoControl(); } while (!quitgame);
break;
case STRIP:
{
short image=0,text=1;
for(match=0; match<4;
match++,image++,text++)
{
WriteMessage(MSG_GAME,5,5,NEW);
WriteMessage(MSG_1+match,0,5,FOLLOW);
WriteMessage(MSG_OF,0,5,FOLLOW);
WriteMessage(MSG_4,0,5,FOLLOW);
SetUpTable(); Delay(100); DoControl();
if (quitgame) break;
if (winner==COMPLYR) { text=0; image=0; }
FadeScreen(s,DOWN);
LoadIFF(&striptextIFF[stripper],s,NOREFRESH);
BltBitMap(bm,stripinfo[stripper].textx[text],
stripinfo[stripper].texty[text],&bufbm,0,85,
stripinfo[stripper].textdx[text],
stripinfo[stripper].textdy[text],0xc0,31,buffer);
LoadIFF(&stripimageIFF[stripper],s,NOREFRESH);
BltBitMap(bm,stripinfo[stripper].imgx1[image],
stripinfo[stripper].imgy1[image],&bufbm,250,0,
stripinfo[stripper].imgdx[image],
stripinfo[stripper].imgdy[image],0xc0,31,buffer);
for (i=0; i<16; i++)
{ rgb[16+i] = rgb[i]; rgb[i] = RGBroom[i]; }
BltBitMap(bm2,0,0,bm,0,0,320,256,0xc0,31,buffer);
SuperImpose(&bufrp,0,85,rp,101,28,
stripinfo[stripper].textdx[text],
stripinfo[stripper].textdy[text],0,7);
SuperImpose(&bufrp,250,0,rp,
stripinfo[stripper].imgx2[image],
stripinfo[stripper].imgy2[image],
stripinfo[stripper].imgdx[image],
stripinfo[stripper].imgdy[image],0,16);
FadeScreen(s,UP);
if (match==3) PlaySound(&audioinfo[LONGCHEER],64);
ClickDelay(600);
if (match==3 || winner==COMPLYR) break;
arg[OPPONENT]++; DoOptions();
}
break;
}
}
/* enableoptions = FALSE;
if (flipoffer = 1-flipoffer)
{
short flash=0xf00,dirn=-0x100,count=0;
LoadIFF(&offer2IFF,s,VIEW);
while (!(GetMouse()) && ++count < 1500)
{
flash+=dirn;
if (flash==0xf00 || flash==0x400) dirn = -dirn;
colorpalette[1] = flash;
MakeScreen(s); RethinkDisplay();
Delay(2);
}
}
else { LoadIFF(&offerIFF,s,VIEW); ClickDelay(1500); }
*/
} while (Loader(0));
CloseIt();
}
/**********************/
void CueJumpAnim()
{
short y=125,x=180,oldx,oldy,crash=FALSE,
forcex=quicksin[ball[CUE].angle] * 7 / BASE,
forcey=-12,bounce=0,onscreen=TRUE;
ball[CUE].potted = TRUE; ball[CUE].justpotted = TRUE;
ball[CUE].scrnx = ball[CUE].oldscrnx;
ball[CUE].scrny = ball[CUE].oldscrny;
DrawBall(CUE,OFF);
if (forcex > 4) { forcey = -16; crash = TRUE; }
ScreenToFront(s2); ActivateWindow(w2);
SetAPen(rp2,8); PlaySound(&audioinfo[POTTED],64);
while(1)
{
if (onscreen)
{
BltBitMap(bm2,x,y,&bufbm,0,100,8,8,0xc0,31,buffer);
BltPattern(rp2,miniball,x,y,x+7,y+7,2);
}
else Delay(1);
oldx = x; oldy = y;
y+=forcey++/2; x+=forcex;
if (y >= 220+bounce*4)
{
y=220+bounce*2; forcey=-forcey/4; bounce++;
PlaySound(&audioinfo[BOUNCE],32 + 32/bounce);
}
if (bounce==3) Delay(75);
if (onscreen)
{
WaitBeam(oldy+10);
BltBitMap(&bufbm,0,100,bm2,oldx,oldy,8,8,0xc0,31,buffer);
}
if (bounce==3) break;
if (x < 0 || x > 310)
{
if (crash) break;
onscreen=FALSE;
}
}
if (crash)
{
PlaySound(&audioinfo[CRASH],64); Delay(100);
PlaySound(&audioinfo[CHEER],64);
}
WriteMessage(MSG_OOOPS,30,5,NEW);
ScreenToFront(s); ActivateWindow(w);
}
/*************************/
void DoControl()
{
short input,i,key=0;
if (gametype==PRACTICE || dragcheat) SetPointer(w,pointeron,11,11,0,0);
WriteMessage(player[turn].nametag,5,5,NEW); GetInput();
quitgame = FALSE; endofgame = FALSE;
do
{
input = GetInput();
if (gametype==DEMO || (gametype==PLYR1 && turn==COMPLYR))
{
if (input==ESC) quitgame=TRUE;
else PlayComputerShot();
}
else switch(input)
{
case ESC: quitgame=TRUE; break;
case RETURN:
{
BOOL play=TRUE;
if (ChangeSpin()==FALSE) play=FALSE;
else do { input = GetInput(); ChangePower(); }
while (!(input==RETURN || input==ESC));
if (input==ESC) play=FALSE;
if (play) PlayShot();
else
{
WriteMessage(MSG_SHOTCANCELLED,5,5,NEW);
cuespeed=MINSPEED; Delay(50);
WriteMessage(player[turn].nametag,5,5,NEW);
}
} break;
case LCSR: MoveCue(CLOCKWISE,SMALL); break;
case RCSR: MoveCue(ANTICLOCKWISE,SMALL); break;
case UCSR: MoveCue(CLOCKWISE,LARGE); break;
case DCSR: MoveCue(ANTICLOCKWISE,LARGE); break;
case SPACE: do ChangePower(); while (cuespeed < (MAXSPEED/2));
PlayShot(); break;
case F1: DrawCue(OFF);
if ((dotspacing+=2) > 12) dotspacing=4;
DrawCue(ON); break;
case F2: player[2].cuepulls = 1-player[2].cuepulls;
player[0].cuepulls = player[2].cuepulls;
player[3].cuepulls = 1-player[3].cuepulls;
player[1].cuepulls = player[3].cuepulls;
cuespeed=MAXSPEED; DrawCue(OFF);
DrawCue(HIT); DrawCue(ON); cuespeed=MINSPEED; break;
case F3: DrawCue(OFF); cueline=(1-cueline); DrawCue(ON); break;
case F4: /* cheer toggle */
if (cheer = 1-cheer) PlaySound(&audioinfo[CHEER],64);
break;
case F5: /* smash balls */
if (gametype==PRACTICE || dragcheat)
{
for (i=0; i<balls; i++)
{
ball[i].angle = Rand(360);
ball[i].speed = MAXSPEED;
}
cuespeed = MAXSPEED; PlayShot();
} break;
case F6: if (gametype==PRACTICE || dragcheat)
{
DrawCue(OFF); SetUpTable();
WriteMessage(player[turn].nametag,5,5,NEW);
} break;
case 37: /* "hogan" win game cheat!!! */ key = 10; break;
case 24: if (key==10) key = 20; break;
case 36: if (key==20) key = 30; break;
case 32: if (key==30) key = 40; break;
case 54: if (key==40) { endofgame=TRUE; winner=HUMANPLYR; }
break;
case 25: /* "pixie" dragball cheat!!! */ key = 1; break;
case 23: if (key==1) key = 2; if (key==3) key = 4; break;
case 50: if (key==2) key = 3; break;
case 18: if (key==4)
{
if (dragcheat=1-dragcheat)
SetPointer(w,pointeron,11,11,0,0);
else SetPointer(w,pointeroff,1,1,0,0);
} break;
case HELP: if (gametype==PRACTICE || dragcheat)
PlayComputerShot(); break;
}
if (quitgame)
{
if (gametype==DEMO)
{
if (defaultdemo) for(i=0; i<8; i++) arg[i] = bufarg[i];
defaultdemo=FALSE;
WriteMessage(MSG_QUITTING,5,5,NEW); Delay(50);
}
else
{
WriteMessage(MSG_QUITGAME,5,5,NEW);
do input = GetInput();
while (input!=21 && input!=54);
if (input==54)
{
WriteMessage(player[turn].nametag,5,5,NEW);
quitgame=FALSE;
}
else { WriteMessage(MSG_QUITTING,5,5,NEW); Delay(50); }
}
}
if (endofgame && gametype!=PRACTICE)
{
player[winner].wins++;
if (gametype==PLYR1)
{
if (winner==HUMANPLYR)
{
WriteMessage(MSG_WELLDONE,5,5,NEW);
if (cheer) PlaySound(&audioinfo[LONGCHEER],64);
}
else WriteMessage(MSG_BADLUCK,5,5,NEW);
Delay(75);
}
else if (cheer) PlaySound(&audioinfo[LONGCHEER],64);
WriteMessage(player[winner].nametag,5,5,NEW);
WriteMessage(MSG_WINS,0,5,FOLLOW);
Delay(100); ScrubMessage();
if (defaultdemo) for(i=0; i<8; i++) arg[i] = bufarg[i];
defaultdemo=FALSE;
}
if (gametype==PRACTICE || dragcheat) CheckBallDrag();
} while(!quitgame && !endofgame);
DrawCue(OFF); SetPointer(w,pointeroff,1,1,0,0);
}
/**********************/
void DrawCue(status)
short status;
{
short i,j,x1,y1,x2,y2,dx,dy,dirnlen=0,cuelen=MAXCUELENGTH,
viewline=cueline;
if (gametype==DEMO || (gametype==PLYR1 && turn==COMPLYR)) viewline=0;
rp->Mask = 31;
if (status == ON)
{
x1 = X1CORNER + (ball[CUE].x + CUETIP * quicksin[cueangle]
* quicksin[90+spinx/12]/BASE
- spinx/100 * quickcos[cueangle]) / BASE;
y1 = (Y2CORNER-1) - (ball[CUE].y + CUETIP*quickcos[cueangle]
* quicksin[90+spinx/12]/BASE
+ spinx/100 * quicksin[cueangle]) / BASE;
do
{
x2 = x1 + cuelen * quicksin[cueangle]/BASE;
y2 = y1 - cuelen * quickcos[cueangle]/BASE;
cuelen--;
} while (x2 < 1 || x2 > 318 || y2 < 33 || y2 > 254);
blitdat.x = (x1 < x2)? x1-1:x2-1;
blitdat.y = (y1 < y2)? y1-1:y2-1;
blitdat.dx = abs(x1-x2)+3;
blitdat.dy = abs(y1-y2)+3;
BltBitMap(bm,blitdat.x,blitdat.y,&bufbm,
0,0,blitdat.dx,blitdat.dy,0xc0,31,buffer);
SetAPen(rp,_cuecol);
for (dx=-1; dx<2; dx++) for (dy=-1; dy<2; dy++)
{ Move(rp,x1,y1); Draw(rp,x2+dx,y2+dy); }
SetAPen(rp,_ltcuecol); Move(rp,x1,y1); Draw(rp,x2,y2);
SetAPen(rp,_black); WritePixel(rp,x1,y1);
x1 = X1CORNER + ball[CUE].x/BASE - CUETIP*quicksin[cueangle]/BASE;
y1 = (Y2CORNER-1) - ball[CUE].y/BASE + CUETIP*quickcos[cueangle]/BASE;
if (viewline)
{
SetAPen(rp,_white);
for (i=0; i<32; i++,dirnlen+=dotspacing)
{
x2 = x1 - dirnlen * quicksin[cueangle]/BASE;
y2 = y1 + dirnlen * quickcos[cueangle]/BASE;
for (j=0; j<2; j++)
{
if (y2 < (Y1CORNER+7)) y2 += ((Y1CORNER+7)-y2)<<1;
if (y2 > (Y2CORNER-7)) y2 -= (y2-(Y2CORNER-7))<<1;
if (y2 < (Y1CORNER+7)) y2 += ((Y1CORNER+7)-y2)<<1;
if (x2 < (X1CORNER+7)) x2 += ((X1CORNER+7)-x2)<<1;
if (x2 > (X2CORNER-7)) x2 -= (x2-(X2CORNER-7))<<1;
if (x2 < (X1CORNER+7)) x2 += ((X1CORNER+7)-x2)<<1;
}
pixelsave[i].col = ReadPixel(rp,x2,y2);
pixelsave[i].x = x2;
pixelsave[i].y = y2;
}
for (i=0; i<32; i++)
WritePixel(rp,pixelsave[i].x,pixelsave[i].y);
}
}
else if (status==OFF)
{
if (viewline)
{
WaitBOVP(vp);
for (i=31; i>=0; i--)
{
SetAPen(rp,pixelsave[i].col);
WritePixel(rp,pixelsave[i].x,pixelsave[i].y);
}
}
WaitBeam(blitdat.y+blitdat.dy);
BltBitMap(&bufbm,0,0,bm,
blitdat.x,blitdat.y,blitdat.dx,blitdat.dy,0xc0,31,buffer);
}
else if (status==HIT)
{
char firstrun = 0,stage;
short offset;
for (stage=0; stage<player[turn].cuepulls+1; stage++)
for (i=0; i<=180; i+=15)
{
if (stage==player[turn].cuepulls)
offset = quicksin[i]*60*cuespeed/MAXSPEED/BASE;
else offset = (BASE-quickcos[i+i])
*15*cuespeed/MAXSPEED/BASE;
cuelen = MAXCUELENGTH;
x1 = X1CORNER + (ball[CUE].x + CUETIP * quicksin[cueangle]
* quicksin[90+spinx/12]/BASE
- spinx/100 * quickcos[cueangle]
+ offset*quicksin[cueangle]) / BASE;
y1 = (Y2CORNER-1) - (ball[CUE].y + CUETIP*quickcos[cueangle]
* quicksin[90+spinx/12]/BASE
+ spinx/100 * quicksin[cueangle]
+ offset*quickcos[cueangle]) / BASE;
if (x1 < 1 || x1 > 318 || y1 < 33 || y1 > 254) continue;
do
{
x2 = x1 + cuelen * quicksin[cueangle]/BASE;
y2 = y1 - cuelen * quickcos[cueangle]/BASE;
cuelen--;
} while (x2 < 1 || x2 > 318 || y2 < 33 || y2 > 254);
if (!firstrun)
{
Delay(1); WaitBeam(blitdat.y+blitdat.dy);
BltBitMap(&bufbm,0,0,bm,blitdat.x,blitdat.y,
blitdat.dx,blitdat.dy,0xc0,31,buffer);
}
blitdat.x = (x1 < x2)? x1-1:x2-1;
blitdat.y = (y1 < y2)? y1-1:y2-1;
blitdat.dx = abs(x1-x2)+3;
blitdat.dy = abs(y1-y2)+3;
BltBitMap(bm,blitdat.x,blitdat.y,&bufbm,
0,0,blitdat.dx,blitdat.dy,0xc0,31,buffer);
SetAPen(rp,_cuecol);
for (dx=-1; dx<2; dx++) for (dy=-1; dy<2; dy++)
{ Move(rp,x1,y1); Draw(rp,x2+dx,y2+dy); }
SetAPen(rp,_ltcuecol); Move(rp,x1,y1); Draw(rp,x2,y2);
SetAPen(rp,_black); WritePixel(rp,x1,y1);
firstrun = 0;
}
WaitBeam(blitdat.y+blitdat.dy);
BltBitMap(&bufbm,0,0,bm,blitdat.x,blitdat.y,
blitdat.dx,blitdat.dy,0xc0,31,buffer);
}
}
/***********************/
void MakeCollision(i,j)
short i,j;
{
short dx,dy,volume,theta,dxi,dxj,dyi,dyj,
reldx,reldy,relspeed,relangle,
passx,passy,transfer,intersect,jump=FALSE;
dx = ball[j].x - ball[i].x;
dy = ball[j].y - ball[i].y;
intersect = BALLDIAMETER - QuickRoot(dx*dx + dy*dy);
if (i==CUE && ball[CUE].speed > (MAXSPEED*3/4) &&
spiny < -600 && !(Rand(2))) { jump=TRUE; CueJumpAnim(); }
/* Find pure offsets */
dxi = ball[i].speed * quicksin[ball[i].angle] / BASE;
dyi = ball[i].speed * quickcos[ball[i].angle] / BASE;
dxj = ball[j].speed * quicksin[ball[j].angle] / BASE;
dyj = ball[j].speed * quickcos[ball[j].angle] / BASE;
/* Ball i relative offsets - makes ball j static */
reldx = dxi - dxj;
reldy = dyi - dyj;
relspeed = QuickRoot(reldx*reldx + reldy*reldy);
/* Reposition balls so that they collide at surface */
if (relspeed > BASE && packstate==SPREAD)
{
dx = (ball[j].x - dxj * intersect / relspeed) -
(ball[i].x - dxi * intersect / relspeed);
dy = (ball[j].y - dyj * intersect / relspeed) -
(ball[i].y - dyi * intersect / relspeed);
}
theta = FindAngle(dx,dy,BALLDIAMETER);
/* Common angle between balls */
relangle = FindAngle(reldx,reldy,relspeed);
/* Find angle of relative velocity */
/* Power transfer from one ball to another */
transfer = abs(quickcos[abs(theta - relangle)])*relspeed*3/BASE/4;
passx = transfer * quicksin[theta] / BASE;
passy = transfer * quickcos[theta] / BASE;
if (i==CUE && spiny)
{
dxi += dxi * spiny / 800 *
abs(quickcos[abs(theta - relangle)]) / BASE;
dyi += dyi * spiny / 800 *
abs(quickcos[abs(theta - relangle)]) / BASE;
spiny=0; swerve=0;
}
dxj += passx; dyj += passy;
dxi -= passx; dyi -= passy;
ball[i].speed = QuickRoot(dxi*dxi + dyi*dyi);
if (ball[i].speed > MAXSPEED) ball[i].speed = MAXSPEED;
else if (ball[i].speed < 6) ball[i].speed = 6;
if (ball[i].speed) ball[i].angle = FindAngle(dxi,dyi,ball[i].speed);
ball[j].speed = QuickRoot(dxj*dxj + dyj*dyj);
if (ball[j].speed > MAXSPEED) ball[j].speed = MAXSPEED;
else if (ball[j].speed < 6) ball[j].speed = 6;
if (ball[j].speed) ball[j].angle = FindAngle(dxj,dyj,ball[j].speed);
if (i==CUE && spinx)
{
ball[CUE].angle-=spinx/25;
CheckAngle(&ball[CUE].angle);
spinx=0; swerve=0;
}
ball[i].lasthit = j; ball[j].lasthit = i;
if (cheatangle!=-1 && j==cheatball)
{
ball[j].angle = cheatangle;
if (ball[j].speed < ball[CUE].speed>>2)
ball[j].speed = ball[CUE].speed>>2;
}
cheatangle=-1;
if ((packstate!=BROKEN || !newbreak) && !jump)
{
/* Prevent multiple collisions on break */
if ((volume = 16 + (transfer<<6)/MAXSPEED) > 64) volume = 64;
PlaySound(&audioinfo[COLLIDE],volume);
if (packstate==RACKED) packstate=BROKEN;
}
/* Check for a foul shot here */
if (i==CUE && !firsthit) firsthit=j;
}
/*********************/
#define ENCRYPTCODE 0xd6
long MyRead(fh,ptr,len)
struct FileHandle *fh;
long *ptr;
long len;
{
long retnlen;
retnlen = Read((BPTR)fh,ptr,len);
len = retnlen;
{
register char *ptr2 = (char *)ptr;
while (len > 3)
{
*ptr2++ ^= ENCRYPTCODE; *ptr2++ ^= ENCRYPTCODE;
*ptr2++ ^= ENCRYPTCODE; *ptr2++ ^= ENCRYPTCODE;
len -= 4;
}
while (len) { *ptr2++ ^= ENCRYPTCODE; len--; }
}
return retnlen;
}